#set( $symbol_pound = '#' )
#set( $symbol_dollar = '$' )
#set( $symbol_escape = '\' )
package ${package};

import javassist.CannotCompileException;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.NotFoundException;

import org.slf4j.Logger;

import com.google.code.instrumentation.util.CompileTimeClassUtil;

public class MyMethodInstrumentor extends AbstractMethodInstrumentor {

	protected MyMethodInstrumentor(final CtMethod method) {
		super(method);
	}

	@Override
	public void addLogEnd() throws CannotCompileException {
		final String methodName = ctMethod.getName();
		final boolean asFinally = true;

		try {
			ctMethod.addLocalVariable("elapsedTime",
					CompileTimeClassUtil.getCtClassFor(long.class));
		} catch (final NotFoundException e) {
			// Should not happen
			throw new RuntimeException("Failed to find JRE class", e);
		}

		// We don't have access to the local variable. So just output the log message twice for now!
		ctMethod.insertAfter("elapsedTime = System.currentTimeMillis() - startTime;");
		
		// TODO - Invoke the appropriate log message at TRACE level (or equivalent)
		// This reference implementation is based on slf4J
		ctMethod.insertAfter("log.trace(${symbol_escape}"EXIT: [{}] ElapsedTime: {}ms${symbol_escape}", new Object[] {methodName,Long.valueOf(elapsedTime)});");

		// TODO - Invoke the appropriate log message at TRACE level (or equivalent)
		// This reference implementation is based on slf4J
		ctMethod.insertAfter(
				String.format(
						"org.slf4j.LoggerFactory.getLogger(this.getClass()).trace(${symbol_escape}"EXIT: [{}]${symbol_escape}",new Object[]{${symbol_escape}"%s${symbol_escape}"});",
						methodName), asFinally);
	}

	@Override
	public void addLogStart() throws CannotCompileException {
		try {
			
			// TODO - Add specify logging implementation class
			final CtClass loggingClass = CompileTimeClassUtil
					.getCtClassFor(null.class);
			ctMethod.addLocalVariable("log", loggingClass);
			final CtClass stringClass = CompileTimeClassUtil
					.getCtClassFor(String.class);
			ctMethod.addLocalVariable("methodName", stringClass);
			final CtClass longClass = CompileTimeClassUtil
					.getCtClassFor(long.class);
			ctMethod.addLocalVariable("startTime", longClass);

			final String methodName = ctMethod.getName();

			// subsequent insert statements mean that the final statement
			// order is in reverse
			
			// TODO - Invoke the appropriate log message at TRACE level (or equivalent)
			// This reference implementation is based on slf4J
			ctMethod.insertBefore("log.trace(${symbol_escape}"ENTRY: [{}({})]${symbol_escape}", new Object[] {methodName, java.util.Arrays.deepToString(${symbol_dollar}args)});");
			
			// TODO - Lookup the appropriate logger (this must be fully qualified)
			ctMethod.insertBefore("log = org.slf4j.LoggerFactory.getLogger(this.getClass());");
			
			ctMethod.insertBefore("methodName = ${symbol_escape}"" + methodName + "${symbol_escape}";");
			ctMethod.insertBefore("startTime = System.currentTimeMillis();");

		} catch (final NotFoundException e) {
			throw new CannotCompileException(e);
		}
	}

}
